package br.unicamp.ic.mc906.TextProcessing;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;

import br.unicamp.ic.mc906.kmeans.Kmeans;
import br.unicamp.ic.mc906.kmeans.test.Message;

/**
 * Classe responsavel por desmontar uma mensagem e montar uma classe clusterizavel
 * 
 *
 */
public class TextProcessing3 {

	private static List<Message> messages;
	
	private static List<String> stopWords;
	
	private static List<String> fileNames;

	private static int current;
	
	public static String getFileAsString(String mensagem) {
		File file = new File(Settings.MESSAGES_DIRECTORY+"/"+mensagem);
		try {
			BufferedReader bf = new BufferedReader(new FileReader(file));
			String line = "";
			while (bf.ready()) {
				line += bf.readLine();
			}
			return line;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return "";
	}
	
	public static boolean MultThreadReading(int numberOfFiles) {
		List<Thread> threads = new ArrayList<Thread>(); 
		for (current = 0; current < numberOfFiles;) {

			for (int i = 0; i < 16 && current < numberOfFiles; i++) {
				threads.add(new Thread(new Runnable() {
					
					Message novo;

					@Override
					public void run() {
						String textoTotal = getFileAsString(fileNames.get(current));
						novo = new Message(fileNames.get(current));
						filterAndExtractFrequency(textoTotal);
						novo.setGroup(getGroupMessage(novo.getName()));
						messages.add(novo);
					}

					private void filterAndExtractFrequency(String textoTotal) {
						// Filtra pela stop words e monta o Map de frenquencia
						StringTokenizer st = new StringTokenizer(textoTotal);
						while (st.hasMoreElements()) {
							String element = st.nextToken();
							// Adiciona elementos com lowerCase e sem espa�o. 
							if (!stopWords.contains(element.toLowerCase().trim())) {
								if (novo.getFrequencia().containsKey(element.toLowerCase().trim())) {
									Integer frequencia = novo.getFrequencia().get(element.toLowerCase().trim());
									novo.getFrequencia().put(element.toLowerCase().trim(), frequencia+1);
								} else {
									novo.getFrequencia().put(element.toLowerCase().trim(), 1);
								}
							}
						}
						// Monta map com as 10 palavras que mais ocorrem.
						Map<String, Integer> maisFrequentes = new TreeMap<String,Integer>();
						List<Integer> maioresValores = new ArrayList<Integer>();
						maioresValores.addAll(novo.getFrequencia().values());
						Collections.sort(maioresValores, new Comparator<Integer>() {
							public int compare(Integer o1, Integer o2) {
								return o1.compareTo(o2)*(-1);
							};
						});
//						System.out.println(maioresValores.size() < 10);
						for (int j = 0; j<20 && j<maioresValores.size(); j++) {
							Integer maiorValor = maioresValores.get(j);
							for (String s : novo.getFrequencia().keySet()) {
								if (novo.getFrequencia().get(s).equals(maiorValor)) {
									maisFrequentes.put(s, maiorValor);
								}
							}
						}
						novo.setMaisFrequentes(maisFrequentes);
					}
					
					public String getGroupMessage(String nome) {
						boolean existeTraco = true;
						int index = 0;
						int last = 0;
						while(existeTraco) {
							String substring = nome.substring(last);
							index = substring.indexOf("-")+1;
							if (index != 0) {
								last += index;
							} else {
								existeTraco = false;
							}
						}
						return nome.substring(0, last);
					}
					
				}));
				threads.get(i).run();
				current++;
				
			}
			
			// Garante que todas as threads foram executadas antes de abrir novas
			boolean execAll = false;
			while (!execAll) {
				execAll = true;
				for (Thread thread : threads) {
					if (thread.isAlive()) {
						execAll = false;
					}
				}
			}
			threads.removeAll(threads);
		}
		
		// Garante que o processo s� volta a executar depois que todos os arquivos foram lidos
		
			
		
		return true;
	}
	
	/**
	 * Metodo usado para impedir que seja adicionado as palavras sem significado
	 * @param language lingua a qual sera aplicada o stopWords
	 */
	public static void loadStopWords(String language) {
		File languageStopWords = new File(Settings.STOPWORDS_DIRECTORY+"/"+language);
		stopWords = new ArrayList<String>();
		try {
			BufferedReader bf = new BufferedReader(new FileReader(languageStopWords));
			while (bf.ready()) {
				stopWords.add(bf.readLine());
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	//Imprime a resposta
	public static void printResults(List<List<Message>> results) {
		for (List<Message> lista : results) {
			Map<String, Integer> densidadeGrupo = new HashMap<String,Integer>();
			// Adiciona o total de ocorrencias de cada grupo
			for (Message t : lista) {
				if(densidadeGrupo.containsKey(t.getGroup())) {
					densidadeGrupo.put(t.getGroup(), densidadeGrupo.get(t.getGroup())+1);
				} else {
					densidadeGrupo.put(t.getGroup(), 1);
				}
			}
			
			// Ordena os elementos de cada grupo
			List<Integer> maisOcorridos = new LinkedList<Integer>();
			maisOcorridos.addAll(densidadeGrupo.values());
			Collections.sort(maisOcorridos, new Comparator<Integer>() {
				@Override
				public int compare(Integer o1, Integer o2) {
					return o1.compareTo(o2)*(-1);
				}
			});
			
			NumberFormat nf = new DecimalFormat();
			nf.setMaximumFractionDigits(2);
			
			int anterior = 0;
			// Procura os mais ocorridos e imprime
			double total = 0;
			for (Integer i : maisOcorridos) {
				if (anterior != i) {
					for(String s : densidadeGrupo.keySet()) {
						if (densidadeGrupo.get(s).equals(i)) {
							Double porcentagem = (((Number)i).doubleValue()/lista.size())*100;
							System.out.println("Nome: "+s+" Total: "+i+" "+nf.format(porcentagem)+"%");
							total += porcentagem;
						}
					}
					anterior = i;
				}
				
				//System.out.println("TOTAL = "+total);
			}
			System.out.println("--------------");
			
		}
	}
	
	public static int calculaPesoPalavra(String palavra){
		int i;
		int soma = 0;
		char c;

		int metade = palavra.length() / 2;
		
		for (i = 0; i < palavra.length() ; i++){
			c = palavra.toLowerCase().charAt(i);
			if (i < metade){
				soma += ((int) c - 64) * (i+1);
			}else{
				soma += ((int) c - 64) * (palavra.length()-i);		
			}
		}
		soma = soma/10;
		return soma;
	}
		
	
	public static void main(String[] args) {
		Date inicio = new Date();
		File diretorio = new File(Settings.MESSAGES_DIRECTORY);
		fileNames = new LinkedList<String>();
		loadStopWords("english");
		
		// Adiciona os 100 primeiros textos no vetor.
		for (int i = 1; i < 100; i++) {
			fileNames.add(diretorio.list()[((Number)(Math.random()*diretorio.list().length)).intValue()]);
//			fileNames.add(diretorio.list()[i]);
		}
		// Faz a leitura
		messages = new LinkedList<Message>();
		MultThreadReading(fileNames.size());

		
		for (Message m : messages){
			int somaFreq = 0;
			int somaPeso = 0;
			
			List<Integer> maioresValores = new ArrayList<Integer>();
			maioresValores.addAll(m.getFrequencia().values());
			
			Collections.sort(maioresValores, new Comparator<Integer>() {
				public int compare(Integer o1, Integer o2) {
					return o1.compareTo(o2)*(-1);
				};
			});
			
			
			for (int j = 0; j < 10 && j < maioresValores.size(); j++) {
				Integer menorValor = maioresValores.get(maioresValores.size()-j-1);
				
					
				for (String s : m.getFrequencia().keySet()) {
					if (m.getFrequencia().get(s).equals(menorValor)) {
						somaFreq = somaFreq + (menorValor * s.length());
						somaPeso += calculaPesoPalavra(s);
					}
				}
			}
			somaPeso = somaPeso / 10;
			m.setX(somaPeso);
			m.setY(somaFreq);
		}
		
		Kmeans<Message> km = new Kmeans<Message>();
//		km.cluster(texts, 20);
		printResults(km.cluster(messages, 20));
		
		Date fim = new Date();
		
		System.out.println("Tempo de execu��o foi de "+(fim.getTime()-inicio.getTime())/1000+" segundos");
		
//		text.getFrequencia();
//		System.out.println(text.getText());
	}
	
	
}
